package org.qpcr.community.auth.web;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.hswebframework.reactor.excel.ReactorExcel;
import org.hswebframework.web.api.crud.entity.PagerResult;
import org.hswebframework.web.api.crud.entity.QueryParamEntity;
import org.hswebframework.web.authorization.Authentication;
import org.hswebframework.web.authorization.annotation.Authorize;
import org.hswebframework.web.authorization.annotation.QueryAction;
import org.hswebframework.web.authorization.annotation.Resource;
import org.hswebframework.web.authorization.annotation.SaveAction;
import org.hswebframework.web.authorization.exception.UnAuthorizedException;
import org.hswebframework.web.crud.query.QueryHelper;
import org.qpcr.community.auth.entity.UserDetail;
import org.qpcr.community.auth.entity.UserDetailEntity;
import org.qpcr.community.auth.enums.UserEntityType;
import org.qpcr.community.auth.enums.UserEntityTypes;
import org.qpcr.community.auth.service.UserDetailService;
import org.qpcr.community.auth.service.request.SaveUserDetailRequest;
import org.qpcr.community.auth.service.request.SaveUserRequest;
import org.qpcr.community.auth.web.excel.ImportResult;
import org.qpcr.community.auth.web.excel.UserExcelFilterColumns;
import org.qpcr.community.auth.web.excel.UserExcelInfo;
import org.qpcr.community.entity.LogMessageEntity;
import org.qpcr.community.service.LogMessageServices;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.logging.LogManager;

@RestController
@RequestMapping("/user/detail")
@AllArgsConstructor
@Tag(name = "用户信息接口")
@Resource(id = "user", name = "系统用户", group = "system")
@Slf4j
public class UserDetailController {

    private final UserDetailService userDetailService;
    private final UserExcelFilterColumns filterColumns;
    private final LogMessageServices logService;

    @PostMapping("/_create")
    @SaveAction
    @Operation(summary = "创建用户")
    @Transactional
    public Mono<String> createUser(@RequestBody Mono<SaveUserRequest> body) {
        return body
            .flatMap(userDetailService::saveUser);
    }

    @PutMapping("/{userId}/_update")
    @SaveAction
    @Operation(summary = "修改用户")
    public Mono<String> updateUser(@PathVariable String userId,
                                   @RequestBody Mono<SaveUserRequest> body) {
        return body
            .doOnNext(request -> {
                if (request.getUser() != null) {
                    request.getUser().setId(userId);
                }
            })
            .flatMap(userDetailService::saveUser);
    }

    @GetMapping("/{userId}")
    @SaveAction
    @Operation(summary = "获取用户详情信息")
    public Mono<UserDetail> getUserDetail(@PathVariable String userId) {
        return userDetailService.findUserDetail(userId);
    }

    @PostMapping("/_query")
    @QueryAction
    @Operation(summary = "分页获取用户详情")
    public Mono<PagerResult<UserDetail>> queryUserDetail(@RequestBody Mono<QueryParamEntity> query) {
        return query.flatMap(userDetailService::queryUserDetail);
    }

    /**
     * 获取当前登录用户详情
     *
     * @return 用户详情
     */
    @GetMapping
    @Operation(summary = "获取当前登录用户详情")
    @Authorize(merge = false)
    public Mono<UserDetail> getCurrentLoginUserDetail() {
        return Authentication
            .currentReactive()
            .switchIfEmpty(Mono.error(UnAuthorizedException::new))
            .flatMap(autz -> userDetailService
                .findUserDetail(autz.getUser().getId())
                .switchIfEmpty(Mono.fromSupplier(() -> new UserDetail().with(autz)))
            );
    }

    /**
     * 保存当前用户详情
     *
     * @return 用户详情
     */
    @PutMapping
    @Operation(summary = "保存当前用户详情")
    @Authorize(merge = false)
    public Mono<Void> saveUserDetail(@RequestBody Mono<SaveUserDetailRequest> request) {
        return Authentication
            .currentReactive()
            .zipWith(request)
            .switchIfEmpty(Mono.error(UnAuthorizedException::new))
            .flatMap(tp2 -> userDetailService.saveUserDetail(tp2.getT1().getUser().getId(), tp2.getT2()));
    }

    @PostMapping("/updateCode")
    @SaveAction
    @Operation(summary = "更新用户二维码信息")
    public Mono<Integer> UpdateUserDetailCode(@RequestBody(required = true) UserDetailEntity ude) {

        return userDetailService.updateUserDetailCode(ude);

    }

    @GetMapping("/validateCode")
    @Operation(summary = "验证二维码字符串是否存在")
    @Authorize(ignore = true)
    public Mono<Integer> validateCode(@Parameter(required = true) String code,String id) {
        if (code ==null ) {
            return Mono.error(new RuntimeException("code不能为空"));
        }
        return userDetailService.validateCode(code ,id);

    }

    @GetMapping("/types")
    @Operation(summary = "获取所有用户类型")
    @Authorize(merge = false)
    public Flux<UserEntityType> getUserEntityTypes() {
        return Flux.fromIterable(UserEntityTypes.getAllType());
    }

    private final QueryHelper queryHelper;
    //原生SQL方式
    @GetMapping("/_detail/_query_native")
    @Authorize(ignore = true)
    public Mono<PagerResult<UserDetail>> nativeJoinExample(@Parameter Long time,@Parameter String deviceId) {
        String sql=" select d.id,d.name,d.code,s.username,s.password,s.salt,d.org_id as orgId ,d.unit_id as unitId,d.telephone,d.role_type roleType ,d.create_time as createTime,d.modify_time as modifyTime ,CASE \n" +
            "        WHEN s.status = 0 THEN 1 \n" +
            "        ELSE d.delete_type \n" +
            "    END AS deleteType " +
            " from s_user_detail d left join s_user s  on d.id=s.id "+
//            " left join biz_relate_dept_device rd on rd.dept_id=d.unit_id "+
            " where  1=1 ";

        if (time!=null && time>0){
            sql+=" and ( d.create_time >"+ time +" or d.modify_time>"+ time +")";
        }
        if (deviceId!=null && !"".equals(deviceId)){

            sql+=" and d.unit_id in( select rd.dept_id from biz_relate_dept_device rd where rd.device_id ='"+ deviceId+"' ) ";
        }

//        LogMessageEntity entity=new LogMessageEntity();
//        entity.setCreateTime(new Date().getTime());
//        entity.setDeviceId(deviceId);
//        entity.setType(3);
//        entity.setDescription("同步了用户信息参数为：time:"+time+",设备ID为："+deviceId);
//        logService.saveLog(entity);


//        Mono<PagerResult<UserDetail>> object=queryHelper
//            .select(sql,
//                    UserDetail::new).fetchPaged();

//        LogMessageEntity entity = new LogMessageEntity();
//        entity.setCreateTime(new Date().getTime());
//        entity.setDeviceId(deviceId);
//        entity.setType(3);
//        entity.setDescription("同步了用户信息参数为：time:"+time+",设备ID为："+deviceId);

        return queryHelper.select(sql, UserDetail::new).fetchPaged()
                          .doOnSuccess(result -> {
                              LogMessageEntity entity = new LogMessageEntity();
                              entity.setCreateTime(new Date().getTime());
                              entity.setDeviceId(deviceId);
                              entity.setType(3);
                              entity.setDescription("同步了用户信息参数为：time:"+time+",设备ID为："+deviceId+"，共查询到 " + result.getTotal() + " 条记录");
//                              logService.saveLog(entity).subscribe(); // 注意这里需要subscribe
                          });
    }

    @GetMapping("/template.xlsx")
    @QueryAction
    @Operation(summary = "下载用户导入模版")
    public Mono<Void> downloadExportTemplate(ServerHttpResponse response) throws IOException {
        response.getHeaders().set(HttpHeaders.CONTENT_DISPOSITION,
                "attachment; filename=".concat(URLEncoder.encode("用户导入模版.xlsx", StandardCharsets.UTF_8
                        .displayName())));
        DataBufferFactory bufferFactory = new DefaultDataBufferFactory();
        return
                Mono.just(new UserDetail())
                        .map(tp1 -> UserExcelInfo.getTemplateHeaderMapping(filterColumns))
                        .defaultIfEmpty(UserExcelInfo.getTemplateHeaderMapping(filterColumns))
                        .flatMapMany(headers ->
                                ReactorExcel.<UserExcelInfo>writer("xlsx")
                                        .headers(headers)
                                        .writeBuffer(Flux.empty()))
                        .doOnError(err -> log.error(err.getMessage(), err))
                        .map(bufferFactory::wrap)
                        .as(response::writeWith);
    }

    @GetMapping(value = "/import/_withlog", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    @SaveAction
    @Operation(summary = "导入用户数据，并提供日志下载")
    public Flux<ImportResult> doBatchImportWithLog(
            @RequestParam @Parameter(description = "文件地址,支持csv,xlsx文件格式") String fileUrl,
            @RequestParam(defaultValue = "32") @Parameter int speed
    ) {
        return userDetailService.doBatchImportWithLog(fileUrl, speed);
    }

}
